﻿using Base.Api.Models;
using Base.Api.Repository;
using Base.Data.Entity;
using Common.AspNetCore;
using Common.Infrastructure;
using Consul;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace Base.Api.Service
{
    public class TokenService : CommonService
    {
        private readonly BaseRepository baseRepository;

        public TokenService(IServiceProvider provider, BaseRepository baseRep) : base(provider)
        {
            this.baseRepository = baseRep;
        }

        public LoginTokenRespose GetToken(LoginTokenRequest request)
        {
            if (request == null || string.IsNullOrEmpty(request.UserName) || string.IsNullOrEmpty(request.Password))
            {
                return null;
            }

            var uuser = this.baseRepository.CommonRepository.GetEntity<t_user>(null, p => p.code.ToUpper() == request.UserName.ToUpper());
            if (uuser != null)
            {
                var member = this.baseRepository.CommonRepository.GetEntity<t_member>(null, i => i.user_id == uuser.id && i.password.ToUpper() == request.Password.ToUpper() && i.enable_status == 0);
                if (member == null)
                {
                    return null;
                }

                var members = this.baseRepository.CommonRepository.GetEntities<t_member>(p => p.user_id == uuser.id && p.enable_status == 0);

                if (members == null || !members.Any())
                {
                    return null;
                }

                if (members.Count == 1)
                {
                    return GetLoginTokenRespose(members.FirstOrDefault(), uuser, request);
                }

                var token = GetLoginTokenRespose(member, uuser, request);
                token.Type = 1;
                var orgIds = members.Select(t => t.org_id).Distinct().ToList();
                var orgs = this.baseRepository.CommonRepository.GetEntities<t_organization>(orgIds);
                members.ForEach(o =>
                {
                    if (token.LoginTokenMembers.Any(t3 => t3.OrgId == o.org_id))
                    {
                        return;
                    }

                    token.LoginTokenMembers.Add(new LoginTokenMember
                    {
                        MemberId = o.id,
                        MemberCode = o.code,
                        MemberName = o.name,
                        OrgId = o.org_id,
                        OrgName = orgs.FirstOrDefault(p => p.id == o.org_id)?.name,
                        IQCPowerLevel = o.iqc_power_level,
                        ApiKey = o.api_key,
                        AreaId = o.area_id
                    });
                });

                return token;
            }
            else
            {
                var member = this.baseRepository.CommonRepository.GetEntity<t_member>(null, i => i.code.ToUpper() == request.UserName.ToUpper() && i.password.ToUpper() == request.Password.ToUpper());
                if (member == null)
                {
                    return null;
                }

                var user = this.baseRepository.CommonRepository.GetEntity<t_user>(member.user_id);
                return GetLoginTokenRespose(member, user, request);
            }
        }

        public LightAppLoginTokenRespose GetLightAppToken(LoginLightAppTokenRequest request)
        {
            var token = new LightAppLoginTokenRespose();
            if (request.Type == 1)
            {
                if (string.IsNullOrEmpty(request.UserName) || string.IsNullOrEmpty(request.Password))
                {
                    return null;
                }
            }
            else
            {
                if (string.IsNullOrEmpty(request.UserName))
                {
                    return null;
                }
            }

            var user = this.baseRepository.CommonRepository.GetEntity<t_user>(null, i => i.user_lcp_code.ToUpper() == request.UserName.ToUpper());
            if (user == null)
            {
                return null;
            }

            var members = this.baseRepository.CommonRepository.GetEntities<t_member>(p => p.user_id == user.id);
            if (members == null || !members.Any())
            {
                return null;
            }

            if (request.Type == 1)
            {
                var member = members.FirstOrDefault(p => p.password.ToUpper() == request.Password.ToUpper());
                if (member != null)
                {
                    user = this.baseRepository.CommonRepository.GetEntity<t_user>(member.user_id);
                    token.LoginToken = GetLoginTokenRespose(member, user, request);
                    var org = this.baseRepository.CommonRepository.GetEntity<t_organization>(token.LoginToken.OrgId);
                    token.ApiKey = org?.api_key;
                }
                else
                {
                    return null;
                }
                ////else
                ////{
                ////    var user = this.baseRepository.CommonRepository.GetEntity<t_user>(null, p => p.code.ToUpper() == request.UserName.ToUpper());
                ////    if (user != null)
                ////    {
                ////        var members = this.baseRepository.CommonRepository.GetEntities<t_member>(p => p.user_id == user.id && p.password.ToUpper() == request.Password.ToUpper());
                ////        if (members == null || !members.Any())
                ////        {
                ////            return null;
                ////        }
                ////        else if (members.Count == 1)
                ////        {
                ////            token.LoginToken = GetLoginTokenRespose(members.FirstOrDefault(), user, request);
                ////            var org = this.baseRepository.CommonRepository.GetEntity<t_organization>(token.LoginToken.OrgId);
                ////            token.ApiKey = org?.api_key;
                ////        }
                ////        else
                ////        {
                ////            token.LoginToken = GetLoginTokenRespose(members.FirstOrDefault(), user, request);
                ////            token.LoginToken.Type = 1;
                ////            var orgs = this.baseRepository.CommonRepository.GetEntities<t_organization>(p => members.Select(t => t.org_id).Contains(p.id));
                ////            members.ForEach(o =>
                ////            {
                ////                token.LoginToken.LoginTokenMembers.Add(new LoginTokenMember
                ////                {
                ////                    MemberId = o.id,
                ////                    MemberCode = o.code,
                ////                    MemberName = o.name,
                ////                    OrgId = o.org_id,
                ////                    ApiKey = orgs.FirstOrDefault(p => p.id == o.org_id)?.api_key,
                ////                    OrgName = orgs.FirstOrDefault(p => p.id == o.org_id)?.name
                ////                });
                ////            });
                ////        }
                ////    }
                ////}
            }
            else
            {
                if (members.Count == 1)
                {
                    token.LoginToken = GetLoginTokenRespose(members.FirstOrDefault(), user, request);
                    var org = this.baseRepository.CommonRepository.GetEntity<t_organization>(token.LoginToken.OrgId);
                    token.ApiKey = org?.api_key;
                }
                else
                {
                    token.LoginToken = GetLoginTokenRespose(members.FirstOrDefault(), user, request);
                    token.LoginToken.Type = 1;
                    var orgs = this.baseRepository.CommonRepository.GetEntities<t_organization>(p => members.Select(t => t.org_id).Contains(p.id));
                    members.ForEach(o =>
                    {
                        token.LoginToken.LoginTokenMembers.Add(new LoginTokenMember
                        {
                            MemberId = o.id,
                            MemberCode = o.code,
                            MemberName = o.name,
                            OrgId = o.org_id,
                            ApiKey = orgs.FirstOrDefault(p => p.id == o.org_id)?.api_key,
                            OrgName = orgs.FirstOrDefault(p => p.id == o.org_id)?.name
                        });
                    });
                }
            }

            return token;
        }

        private LoginTokenRespose GetLoginTokenRespose(t_member member, t_user user, LoginTokenRequest request)
        {
            var authTime = DateTime.Now;
            var expiresTime = authTime.AddDays(10);
            var userToken = new UserToken
            {
                Id = member.id,
                UId = member.user_id,
                Nm = member.name,
                OrgId = member.org_id,
                Lg = request.Lang,
                AreaId = user.area_id,
            };

            var claims = new[]
            {
                    new Claim(JwtRegisteredClaimNames.Nbf, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"),
                    new Claim(JwtRegisteredClaimNames.Exp, $"{new DateTimeOffset(expiresTime).ToUnixTimeSeconds()}"),
                    new Claim(ClaimTypes.Name, request.UserName),
                    new Claim("UserData", userToken.ToJson())
                };

            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("MGRmYjc3ODg4ZDQ2NDE0ZTkxZWNiZjcxNjY1NTIwMWQ="));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            var token = new JwtSecurityToken(
                issuer: "leedarson.com",
                audience: "leedarson.com",
                claims: claims,
                expires: expiresTime,
                signingCredentials: creds);

            return new LoginTokenRespose()
            {
                MemberId = member.id,
                OrgId = member.org_id,
                Token = token,
                ExpireTime = expiresTime,
                AuthTime = authTime,
                UserId = member.user_id,
                UserCode = user.code,
                MemberName = member.name,
                MemberCode = member.code,
                AreaId = member.area_id,
                IQCPowerLevel = member.iqc_power_level,
            };
        }
    }
}
